#include "assert.h"
#include "error.h"
#include "fs/deffs.h"
#include "fs/inode.h"
#include "fs/iobuf.h"
#include "fs/vfs.h"
#include "proc.h"
#include "type.h"

int
vfs_open(char* path, uint32_t flags, inode_t** node_store) {
    bool writeable = FALSE;
    switch (flags & O_ACCMODE) {
        case O_RDONLY:
            break;
        case O_WRONLY:
        case O_RDWR:
            writeable = TRUE;
            break;
        default:
            return -E_INVAL;
    }

    if ((flags & O_TRUNC) && !writeable)
        return -E_INVAL;

    bool excl = ((flags & O_EXCL) != 0);
    bool create = ((flags & O_CREATE) != 0);

    inode_t* node;
    int ret = vfs_lookup(path, &node);
    if (ret != 0) {
        if (ret == -E_NOENTRY && create) {
            char* name;
            inode_t* dir;
            ret = vfs_lookupParent(path, &dir, &name);
            if (ret != 0)
                return ret;
            ret = vop_create(dir, name, excl, &node);
        } else
            return ret;
    } else if (excl && create)
        return -E_EXISTS;

    assert(node != NULL);
    ret = vop_open(node, flags);
    if (ret != 0) {
        vop_refDec(node);  //?
        return ret;
    }

    vop_openInc(node);  //?
    if (flags & O_TRUNC || create) {
        ret = vop_truncate(node, 0);
        if (ret != 0) {
            vop_openDec(node);
            vop_refDec(node);
            return ret;
        }
    }
    *node_store = node;
    return 0;
}

int
vfs_close(inode_t* node) {
    vop_openDec(node);
    vop_refDec(node);
    return 0;
}

int
vfs_unlink(char* path) {}

int
vfs_rename(char* oldPath, char* newPath) {}

int
vfs_link(char* oldPath, char* newPath) {}

int
vfs_symlink(char* oldPath, char* newPath) {
}